#!/usr/bin/env python

import sys, re, urllib, urllib2, urlparse, hashlib, traceback, os.path
import json, base64, traceback

API_END_POINT = 'http://api.smugmug.com/services/api/json/1.2.2/'
API_RAW_UPLOAD_URL = 'http://upload.smugmug.com/photos/xmlrawadd.mg'
API_KEY = 'cSzkRTzVbleJokXYBmhh0lOICYRaq7A7'
API_VERSION = '1.2.2'

class SmirkCall(object):
    def __init__(self, params, headers=None, data=None, maxErrors=2):
        self.params = params
        self.headers = headers
        self.data = data
        self.url = None
        self.result = None
        self.maxErrors = maxErrors

    def call(self):
        assert(self.params.has_key('method'))
        self.request(API_END_POINT, self.params)

    def post(self):
        assert(self.headers is not None and self.data is not None)
        self.request(API_RAW_UPLOAD_URL, self.params)

    def joinRequestParams(self, params):
        paramStringList = []
        for key,value in params.items():
            item = urllib.quote(key) + '=' + urllib.quote(value) 
            paramStringList.append(item)
        return '&'.join(paramStringList)

    def request(self, baseurl, params):
        errorCnt = 0
        while True:
            try:
                paramString = self.joinRequestParams(params)
                self.url = urlparse.urljoin(baseurl, '?' + paramString)
                if self.headers and self.data:
                    request = urllib2.Request(self.url, self.data, self.headers)
                else:
                    request = urllib2.Request(self.url)
                responseObj = urllib2.urlopen(request)
                response = responseObj.read()
                self.result = json.loads(response)
                if self.result['stat'] == 'ok':
                    break
            except Exception,e:
                self.result = None
                errorCnt += 1
                #if errorCnt >= self.maxErrors:
                #    raise Exception("MaxErrors was reached in connection")
                if self.headers is None:
                    print >>sys.stderr, 'Exception on request:',e
                    print >>sys.stderr, 'while trying:',self.url
                else:
                    print >>sys.stderr, os.getpid(),'headers:',base64.b64decode(self.headers['X-Smug-FileName'])
                print >>sys.stderr, os.getpid(),'Error Count:',errorCnt
                #traceback.print_stack()
                traceback.print_exc()
                #break

class Session(object):
    def __init__(self, email, password):
        self.email = email
        self.password = password

    def getSessionIdParams(self):
        return {'SessionID' : self.id}

    def login(self):
        params = {'APIKey'       : API_KEY,
                  'EmailAddress' : self.email,
                  'Password'     : self.password,
                  'method': 'smugmug.login.withPassword'}
        self.sc = SmirkCall(params)
        self.sc.call()
        self.id = self.sc.result['Login']['Session']['id']

class Albums(object):
    def __init__(self, session):
        self.session = session

    def getAlbums(self):
        params = self.session.getSessionIdParams()
        params['method'] = 'smugmug.albums.get'
        sc = SmirkCall(params)
        sc.call()
        return sc.result['Albums']

    def getAlbumByTitle(self, title):
        albums = self.getAlbums()
        found = None
        for album in albums:
            if album['Title'] == title:
                found = album
                break
        return found

    def getAlbumsByTitles(self, titles):
        albums = self.getAlbums()
        found = []
        for album in albums:
            if album['Title'] in titles:
                found.append(album)
        return found

    def getAlbumsByCategoryID(self, categoryID):
        albums = self.getAlbums()
        found = []
        for album in albums:
            if album['Category']['id'] == categoryID:
                found.append(album)
        return found

    def createAlbum(self, title, categoryID=None, albumInfo=None):
        params = self.session.getSessionIdParams()
        params['method'] = 'smugmug.albums.create'
        params['Title'] = title 
        params['Public'] = 'false'
        params['Share'] = 'true'
        params['Unique'] = 'true'
        params['SmugSearchable'] = 'false'
        params['CanRank'] = 'false'
        params['SortMethod'] = 'DateTimeOriginal'
        if albumInfo:
            params.update(albumInfo.params)
        if categoryID:
            params['CategoryID'] = str(categoryID)
        sc = SmirkCall(params)
        sc.call()
        return sc.result['Album']

    def deleteAlbum(self, albumID):
        params = self.session.getSessionIdParams()
        params['method'] = 'smugmug.albums.delete'
        params['AlbumID'] = str(albumID)
        sc = SmirkCall(params)
        sc.call()

class Categories(object):

    def __init__(self, session):
        self.session = session

    def createCategory(self, name):
        params = self.session.getSessionIdParams()
        params['method'] = 'smugmug.categories.create'
        params['Name'] = name
        params['Unique'] = 'true'
        sc = SmirkCall(params)
        sc.call()
        return sc.result['Category']['id']

    def getCategories(self):
        params = self.session.getSessionIdParams()
        params['method'] = 'smugmug.categories.get'
        sc = SmirkCall(params)
        sc.call()
        return sc.result['Categories']

    def getCategoriesByName(self, name):
        cats = self.getCategories()
        found = None
        for cat in cats:
            if name == cat['Name']:
                found = cat
                break
        return found

class ImageUploader(object):
    def __init__(self, session):
        self.session = session

    def upload(self, lfile):
        data = lfile.getData()
        headers = {'Content-Length' : len(data), 
                   'Content-MD5' : lfile.md5, 
                   'Content-Type'     : 'none',
                   'X-Smug-AlbumID' : lfile.album['id'], 
                   'X-Smug-ResponseType' : 'JSON',
                   'X-Smug-SessionID' : self.session.id,
                   'X-Smug-Version' : API_VERSION,
                   'X-Smug-FileName' : lfile.b64fn }
                   #'X-Smug-Keywords' : ,
                   #'X-Smug-Caption' : fn,
        params = {}
        sc = SmirkCall(params, headers, data)
        print os.getpid(),'uploading', lfile.fn
        sc.post()

class Image(object):
    def __init__(self, image):
        self.image = image
        self.id = image['id']
        self.key = image['Key']
        self.md5 = image['MD5Sum']
        self.originalFileName = image['FileName']
        self.fileName = base64.b64decode(self.originalFileName)

    def __eq__(self, other):
        return self.md5 == other.md5

    def __hash__(self):
        return hash(self.md5)

    def __cmp__(self, other):
        return self.md5 < other.md5

    def __str__(self):
        return "Image:" + self.originalFileName

    def __repr__(self):
        return "Image:" + self.originalFileName

class Images(object):
    def __init__(self, session):
        self.session = session

    def getImages(self, albumid, albumkey):
        params = self.session.getSessionIdParams()
        params['method'] = 'smugmug.images.get'
        params['AlbumID'] = str(albumid)
        params['AlbumKey'] = albumkey
        params['Heavy'] = 'true'
        sc = SmirkCall(params)
        sc.call()
        #print sc.result
        album = sc.result['Album']
        images = album['Images']
        out = []
        for image in images:
            out.append( Image(image) )
        return out

    def collect(self, albumID, imageID, imageKey):
        params = self.session.getSessionIdParams()
        params['method'] = 'smugmug.images.collect'
        params['AlbumID'] = str(albumID)
        params['ImageKey'] = imageKey 
        params['ImageID'] = str(imageID)
        sc = SmirkCall(params)
        sc.call()

# vim: set ai et sw=4 ts=4 sts=4 hlsearch
